package com.yanqu.road.server.manager.tomb;

import com.yanqu.road.pb.tomb.Tomb;
import com.yanqu.road.server.logic.MessageHelper;
import com.yanqu.road.server.manager.tomb.entity.DbTombUser;
import com.yanqu.road.server.protocol.GameProtocol;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class TombHeartbeat {

    public static TombHeartbeat newInstance(int activityId) {
        TombHeartbeat tombHeartbeat = new TombHeartbeat();
        tombHeartbeat.activityId = activityId;
        return tombHeartbeat;
    }

    private int activityId;


    private Map<Long, HeartbeatInfo> map = new ConcurrentHashMap<>();

    private Map<String, Map<Long, HeartbeatInfo>> eventMap = new ConcurrentHashMap<>();

    private Map<String, Map<Long, HeartbeatInfo>> unionMap = new ConcurrentHashMap<>();


    public synchronized void handle(DbTombUser dbTombUser, Tomb.TombHeartbeatReq req) {
        if (dbTombUser == null) {
            return;
        }
        HeartbeatInfo heatBeatInfo = this.getHeatBeatInfo(dbTombUser);
        heatBeatInfo.updateDataTime(dbTombUser.getFloor());
        if (!unionMap.containsKey(dbTombUser.getUserInfo().getUnionUid())) {
            unionMap.put(dbTombUser.getUserInfo().getUnionUid(), new ConcurrentHashMap<>());
        }

        if (!unionMap.get(dbTombUser.getUserInfo().getUnionUid()).containsKey(dbTombUser.getUserId())) {
            unionMap.get(dbTombUser.getUserInfo().getUnionUid()).put(dbTombUser.getUserId(), heatBeatInfo);
        }


        Tomb.CoordinateTemp coordinate = req.getCoordinate();
        String key = String.format("%d_%d_%d_%d", dbTombUser.getGroupId(), coordinate.getFloor(), coordinate.getRow(), coordinate.getColumn());
        if (req.getInEvent() == 1) {
            if (!eventMap.containsKey(key)) {
                eventMap.put(key, new ConcurrentHashMap<>());
            }
            if (!eventMap.get(key).containsKey(dbTombUser.getUserId())) {
                eventMap.get(key).put(dbTombUser.getUserId(), heatBeatInfo);
            } else {
                eventMap.get(key).get(dbTombUser.getUserId()).updateDataTime(dbTombUser.getFloor());
            }
            Tomb.TombEventSyncPush.Builder builder = Tomb.TombEventSyncPush.newBuilder();
            builder.setId(dbTombUser.getUserId());
            builder.setOperate(1);
            builder.setEventUserInfo(dbTombUser.toEventUserInfoBuilder());
            Map<Long, Tomb.TombEventSyncPushCrossToGameReq.Builder> toGameReqMap = new HashMap<>();

            Map<Long, HeartbeatInfo> longHeartbeatInfoMap = this.eventMap.get(key);
            if (longHeartbeatInfoMap == null) {
                return;
            }
            for (HeartbeatInfo value : longHeartbeatInfoMap.values()) {
                if (value.getUserId() == dbTombUser.getUserId()) {
                    continue;
                }
                if (!toGameReqMap.containsKey(value.getServerId())) {
                    toGameReqMap.put(value.getServerId(), Tomb.TombEventSyncPushCrossToGameReq.newBuilder().setResp(builder));
                }
                toGameReqMap.get(value.getServerId()).addUserIdList(value.getUserId());

            }
            toGameReqMap.forEach((serverId, _req) -> {
                MessageHelper.sendToGameServer(serverId, GameProtocol.S_TOMB_EVENT_SYNC_PUSH, this.activityId, 0, _req, null);
            });

        } else if (req.getInEvent() == 2) {
            if (eventMap.containsKey(key)) {
                eventMap.get(key).remove(dbTombUser.getUserId());
            }

            Tomb.TombEventSyncPush.Builder builder = Tomb.TombEventSyncPush.newBuilder();
            builder.setId(dbTombUser.getUserId());
            builder.setOperate(2);
            builder.setEventUserInfo(dbTombUser.toEventUserInfoBuilder());
            Map<Long, Tomb.TombEventSyncPushCrossToGameReq.Builder> toGameReqMap = new HashMap<>();
            Map<Long, HeartbeatInfo> longHeartbeatInfoMap = this.eventMap.get(key);
            if (longHeartbeatInfoMap == null) {
                return;
            }
            for (HeartbeatInfo value : longHeartbeatInfoMap.values()) {
                if (value.getUserId() == dbTombUser.getUserId()) {
                    continue;
                }
                if (!toGameReqMap.containsKey(value.getServerId())) {
                    toGameReqMap.put(value.getServerId(), Tomb.TombEventSyncPushCrossToGameReq.newBuilder().setResp(builder));
                }
                toGameReqMap.get(value.getServerId()).addUserIdList(value.getUserId());

            }
            toGameReqMap.forEach((serverId, _req) -> {
                MessageHelper.sendToGameServer(serverId, GameProtocol.S_TOMB_EVENT_SYNC_PUSH, this.activityId, 0, _req, null);
            });
        }
    }


    public HeartbeatInfo getHeatBeatInfo(DbTombUser dbTombUser) {
        HeartbeatInfo heartbeatInfo = this.map.get(dbTombUser.getUserId());
        if (heartbeatInfo != null) {
            return heartbeatInfo;
        }
        heartbeatInfo = HeartbeatInfo.newInstance(dbTombUser);
        this.map.put(heartbeatInfo.getUserId(), heartbeatInfo);
        return heartbeatInfo;
    }


    public List<HeartbeatInfo> getList(int groupId) {
        LocalDateTime now = LocalDateTime.now();
        List<HeartbeatInfo> list = new ArrayList<>();
        for (HeartbeatInfo info : this.map.values()) {
            if(info.getGroupId() != groupId){
                continue;
            }
            if (info.getDateTime().plusSeconds(8).isAfter(now)) {
                list.add(info);
            }
        }
        return list;
    }

    public List<HeartbeatInfo> getUnionList(String unionUid, int floor) {
        LocalDateTime now = LocalDateTime.now();
        List<HeartbeatInfo> list = new ArrayList<>();
        Map<Long, HeartbeatInfo> longHeartbeatInfoMap = this.unionMap.get(unionUid);
        if (longHeartbeatInfoMap == null) {
            return list;
        }

        for (HeartbeatInfo info : longHeartbeatInfoMap.values()) {
            if (info.getFloor() != floor) {
                continue;
            }
            if (info.getDateTime().plusSeconds(8).isAfter(now)) {
                list.add(info);
            }
        }
        return list;
    }

    public List<HeartbeatInfo> getEventList(int floor, int row, int column) {
        String key = String.format("%d_%d_%d", floor, row, column);
        return this.getEventList(key);
    }

    public List<HeartbeatInfo> getEventList(String key) {
        LocalDateTime now = LocalDateTime.now();
        List<HeartbeatInfo> list = new ArrayList<>();
        Map<Long, HeartbeatInfo> longHeartbeatInfoMap = this.eventMap.get(key);
        if (longHeartbeatInfoMap == null) {
            return list;
        }
        for (HeartbeatInfo info : longHeartbeatInfoMap.values()) {
            if (info.getDateTime().plusSeconds(8).isAfter(now)) {
                list.add(info);
            }
        }
        return list;
    }

    public void setActivityId(int activityId) {
        this.activityId = activityId;
    }


    public List<HeartbeatInfo> getOfflineList() {
        LocalDateTime now = LocalDateTime.now();
        List<HeartbeatInfo> list = new ArrayList<>();
        for (HeartbeatInfo heartbeatInfo : this.map.values()) {
            if (heartbeatInfo.getDateTime().plusSeconds(15).isBefore(now)) {
                this.map.remove(heartbeatInfo.getUserId());
                list.add(heartbeatInfo);
            }
        }

        return list;
    }

}

